import RobotModel from "../model/RobotModel";
import { MotionLibrary } from "../motion/MotionLibrary";
import { MotionModuleS } from "../motion/MotionModule";
import { FightState } from "./BoutState";
import { Constants } from "./Constants";
import { StateBase, StateMachine, Transition } from "./StateMachine";

export namespace FightingRobotBehavior {

    export enum EnumRobotState {
        root,
        move2Circle,
        tracePlayer,
    }

    export function getBehavior(targetRobot: RobotModel, fightState:FightState): StateMachine<undefined, EnumRobotState> {
        return new StateMachine<undefined, EnumRobotState>(true)
            .addState(EnumRobotState.root, new BehaviorRoot(targetRobot, fightState))
            .addState(EnumRobotState.move2Circle, new MoveToCircle(targetRobot, fightState))
            .addState(EnumRobotState.tracePlayer, new TracePlayer(targetRobot, fightState))
            .addTransition(new Transition(EnumRobotState.move2Circle, EnumRobotState.root))
            .addTransition(new Transition(EnumRobotState.tracePlayer, EnumRobotState.root))
            .addTriggerTransition(EnumRobotState.move2Circle.toString(), new Transition(EnumRobotState.root, EnumRobotState.move2Circle))
            .addTriggerTransition(EnumRobotState.tracePlayer.toString(), new Transition(EnumRobotState.root, EnumRobotState.tracePlayer))
    }

    // 机器人状态基类
    class FightingRobotState extends StateBase<EnumRobotState>{
        constructor(protected robot:RobotModel, protected fightState:FightState) { 
            super(true)
            fightState.onCircleChanged.add(this.circleChanged, this)
        }

        private circleChanged(){
            if(this.fsm.activeStateID != this.id) return
            this.onCircleChanged()
        }

        protected onCircleChanged(){ }
    }

    // 选择节点
    class BehaviorRoot extends FightingRobotState {
        onEnter(): void {
            let random =  Math.random()
            let selectedState = random < 0.48 ? EnumRobotState.move2Circle.toString() : EnumRobotState.tracePlayer.toString()
            this.fsm.trigger(selectedState)
            this.fsm.canExitCurrent()
        }
    }

    // 朝向圈跑
    class MoveToCircle extends FightingRobotState {
        private currentMoveTarget:Vector
        private arriveCircleCount = 0

        constructor(targetRobot:RobotModel, fightState:FightState) {
            super(targetRobot, fightState);
        }

        onEnter(): void {
            this.resetMoveTarget()
            this.arriveCircleCount = 0
        }

        onUpdate(dt: number): void {
            let ab = Vector.subtract(this.currentMoveTarget, this.robot.position)
            ab.z = 0
            let distance = ab.magnitude
            // 到达目标点
            if(distance <= 40){
                this.resetMoveTarget()
                this.arriveCircleCount++
                // 在圈内跑三次退出一次重新随机状态机
                if(this.arriveCircleCount >= 3){
                    this.fsm.canExitCurrent()
                }
                return
            }
            // 在圈里则跑的慢
            let moveScale = 1
            if(Vector.distance(this.fightState.CircleCenter, this.robot.position) < this.fightState.CircleRadius){
                moveScale = 0.8
            }
            this.robot.moveInput(ab.normalized.multiply(moveScale))
        }

        protected onCircleChanged(){
            if(this.fsm.activeState != this) return
            this.fsm.canExitCurrent()
        }

        // 重置目标点(圈内随机)
        private resetMoveTarget(){
            let center = this.fightState.CircleCenter
            this.currentMoveTarget = new Vector(
                center.x + (Math.cos(Math.random() * 6.283) * (Math.random() * this.fightState.CircleRadius)),
                center.y + (Math.sin(Math.random() * 6.283) * (Math.random() * this.fightState.CircleRadius)),
                center.z
            )
        }
    }

    // 攻击玩家
    class TracePlayer extends FightingRobotState {
        private targetCharacterID:number
        private invokedMotionPendingSecond:number

        constructor(targetRobot:RobotModel, fightState:FightState) {
            super(targetRobot, fightState);
        }

        onEnter(): void {
            this.resetLockTarget()
            this.invokedMotionPendingSecond = undefined
        }

        onUpdate(dt: number): void {
            // 是否已经攻击(攻击后等待后摇结束当前状态)
            if (this.invokedMotionPendingSecond != undefined) {
                this.invokedMotionPendingSecond -= dt;
                if (this.invokedMotionPendingSecond <= 0) this.fsm.canExitCurrent();
                return;
            }
            // 检查当前目标是否还在战斗中
            let index = this.fightState.FightingCharacters.findIndex(fighter => fighter.sceneID == this.targetCharacterID)
            if(index == -1) {
                this.fsm.canExitCurrent()
                return
            }
            // 追击
            let fightCharacter = this.fightState.FightingCharacters[index]
            let targetCharacterPosition = fightCharacter.character.worldTransform.position
            let ab = Vector.subtract(targetCharacterPosition, this.robot.position)
            ab.z = 0
            let distance = ab.magnitude
            // 到达目标点
            if(distance <= 150){
                let motionMD = ModuleService.getModule(MotionModuleS)
                let motion = MotionLibrary.normal_atk
                motionMD.dispatchMotionToAllClient(motion.name, this.robot.sceneID)
                this.invokedMotionPendingSecond = motion.count * Constants.LogicFrameInterval
            }
            // 移动到目标
            else{
                this.robot.moveInput(ab.normalized)
            }
        }

        onCircleChanged(){
            if(this.fsm.activeState != this) return
            this.fsm.canExitCurrent()
        }

        private resetLockTarget() {
            let tempArray = this.fightState.FightingCharacters.filter(c => c.sceneID != this.robot.sceneID)
            if(tempArray.length < 1) return

            this.targetCharacterID = tempArray[Math.floor(tempArray.length * Math.random())].sceneID
        }
    }
}